// This file is part of the ustl library, an STL implementation.
//
// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//


#include "stdtest.h"

class A : public CBase {
public:
    A (string arg) : name(arg)
    { cout << "A::A " << name << endl; }
    ~A (void)
    { cout << "A::~A " << name << endl; }

	string name;
};

class B {
public:
    B (void)
    { cout << "B::B" << endl; }
    ~B (void)
    { cout << "B::~B" << endl; }
    void Close()
    { cout << "B::Close" << endl; }
    B (const B&)
    { cout << "Copy B::B" << endl; }
    const B& operator= (const B&)
    { cout << "B::operator=" << endl; return (*this); }
};

class C {
public:
	C(string name): name_(name) {
		cout << "C:C " << name_<< endl;
		throw exception();
		//throw XLeaveException();
	}
	
	~C() {
		cout << "C::~C" << endl;
	}
	
	string name_;
};

class D {
public:
	D(string name) :name_(name){
		cout << "D::D " << name << endl;
		b_ = new B;
		c_ = new C("throwing constructor");
	}
	
	~D() {
		cout << "D::~D" << endl;
	}
	
	auto_ptr<B> b_;
	auto_ptr<C> c_;
	string name_;
};


void callContructorWithLeavingMember() {
	try {
		auto_ptr<D> leaver(new D("throwing member constructor"));
	}
	catch(exception& e) {
//	catch(XLeaveException& e) {
		cout << "Exception = " << e.Reason() << endl;
	}
}

void callLeavingContructor() {
	try {
		auto_ptr<C> leaver(new C("throwing constructor"));
	}
	catch(exception& e) {
//	catch(XLeaveException& e) {
		cout << "Exception = " << e.Reason() << endl;
	}
}

void callLeaveL()
	{
    A a("on stack");
    
	A* as = new(ELeave) A("on cleanup stack");
	CleanupStack::PushL(as);

	A* ass = new(ELeave) A("2 on cleanup stack");
	CleanupStack::PushL(ass);
	CleanupStack::PopAndDestroy(ass);

	auto_ptr<A> ah(new A("on heap"));

	B bs;
	CleanupClosePushL(bs);
	
	User::Leave(KErrGeneral);
	}

void callThrow()
	{
    A a("on stack");    
	auto_ptr<A> ah(new A("on heap"));

	B bs;
	
	// User::Leave(KErrGeneral); // will cause EUser-Cbase 65
	throw (XLeaveException(-25));
	}

void callThrow2()
	{
    A a("on stack");
    
	A* as = new(ELeave) A("on cleanup stack");
	CleanupStack::PushL(as);

	auto_ptr<A> ah(new A("on heap"));

	B bs;
	CleanupClosePushL(bs);
	
	throw (XLeaveException(-2));
	}

void TestLeaves (void)
{
	cout << "Trap with User::Leave" << endl;
	TRAPD(error,callLeaveL());
	cout << "Error = " << error << endl;

	cout << "Catch with User::Leave" << endl;
	try {
		callLeaveL();
	}
	catch(XLeaveException& ex) {
		cout << "Exception = " << ex.Reason() << endl;
	}

	cout << "Trap with throw" << endl;
	TRAP(error,callThrow());
	cout << "Error = " << error << endl;

	cout << "Catch with throw" << endl;	
	try {
		callThrow();
	}
	catch(XLeaveException& ex) {
		cout << "Exception = " << ex.Reason() << endl;
	}

	cout << "Catch with throw and cleanupstack" << endl;
	try {
		callThrow2();
	}
	catch(XLeaveException& ex) {
		cout << "Exception = " << ex.Reason() << endl;
	}
	cout << "Popping 2 from the cleanupStack - throw did not pop" << endl;	
	CleanupStack::PopAndDestroy(2); 

	cout << "Catch with throw and cleanupstack with guard" << endl;
	TRAP(error, 
	try {
		callThrow2();
	}
	catch(XLeaveException& ex) {
		cout << "Exception = " << ex.Reason() << endl;
		if (ex.Reason() < 0 ) {
			cout << "Leaving again, since this is a Leave" << endl;
			User::Leave(ex.Reason());
		}
	}
	)
	cout << "Error = " << error << endl;
	
	cout << "Trap with throw on cleanupstack - doesnt work!!" << endl;
//	TRAP(error,callThrow2()); // kills thread with kern-exec 27
	cout << "Exception2 = " << error << endl;
	
	cout << "catch a leaving constructor" << endl;
	callLeavingContructor();

	cout << "catch a leaving constructor with member" << endl;
	callContructorWithLeavingMember();
	
	cout << "End" << endl;
}

StdBvtMain (TestLeaves)

